﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

using Microsoft.EntityFrameworkCore;
using treeView.SqlDb.dbModel;
using treeView.SqlDb;
using Nest;
using treeView.PLC;
using treeView.Config;
using System.IO;

namespace treeView
{
    public class Machine
    {
        #region 单例模式
        private static readonly object Lock = new object();
        private static Machine _instance;
        public static Machine Instance
        {
            get
            {
                lock (Lock)
                {
                    if (_instance == null)
                    {
                        _instance = new Machine();
                    }
                }
                return _instance;
            }
        }
        #endregion

        public ConfigDb ConfigDbs { get; private set; }

        public void ConncetConfigDb()
        {
            try
            {
                string path = $"Data Source={AppDomain.CurrentDomain.BaseDirectory}Config\\SCSetting.db";
                var OptionsBuilder = new DbContextOptionsBuilder<SCDBContext>().UseSqlite(path);
                ConfigDbs = new ConfigDb(OptionsBuilder);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"数据库连接出错: {ex.Message}");
                MessageBox.Show($"堆栈跟踪: {ex.StackTrace}");
                if (ex.InnerException != null)
                {
                    MessageBox.Show($"内部异常: {ex.InnerException.Message}");
                    MessageBox.Show($"内部异常堆栈跟踪: {ex.InnerException.StackTrace}");
                }
            }
        }

        #region 配置
        public void ReadConfig()
        {
            ReadCommonConfig();
            BuildPLC();
        }
        private void ReadCommonConfig()
        {
            lock (_lock)
            {
                var workflowConfigPath = $"{AppDomain.CurrentDomain.BaseDirectory}Config\\CommonConfig.json";
                if (!File.Exists(workflowConfigPath))
                {
                    JsonOperation.WriteToJsonFile(new CommonConfig(), workflowConfigPath);
                }
                CommonConfigs = JsonOperation.ReadConfigFromFile<CommonConfig>(workflowConfigPath);
            }
        }
        public IPLC GetPlcByName(string name)
        {
            return Plc.FirstOrDefault(x => x.Name == name);
        }
        public IPLC GetPlcByIndex(int index)
        {
            var plc = Plc.FirstOrDefault(x => x.Index == index);
            return plc;
        }
        public int GetPlcIndex(string name)
        {
            if (Plc.Any(x => x.Name == name))
            {
                return Plc.FirstOrDefault(x => x.Name == name).Index;
            }
            else
            {
                return -1;
            }
        }
        #endregion
        #region 初始化
        private object _lock = new object();
        public List<IPLC> Plc = new List<IPLC>();
        public CommonConfig CommonConfigs { get; set; } = new CommonConfig();


        public bool ThreadRunning = true;
        public void StartUpdate()
        {
            foreach (var item in Plc)
            {
                Task.Run(() =>
                {
                    Update(item);
                });
            }

        }
        private void BuildPLC()
        {
            foreach (var plc in CommonConfigs.PLCS)
            {
                switch (plc.TYPE)
                {
                    case PLCType.OPC:
                        var p = new OPCPLC(plc.Name, plc.Index);
                        p.SetConnectionStr(plc.ConnectStr);
                        Plc.Add(p);
                        break;
                    case PLCType.ADS:
                        break;
                    default:
                        break;
                }
            }
        }
        public void Connect()
        {
            var errorMessages = new List<string>();
            foreach (var item in Plc)
            {
                try
                {
                    item.Connect();
                }
                catch (Exception ex)
                {
                    errorMessages.Add($"连接 {item.Name} 失败: {ex.Message}");
                }
            }
            if (errorMessages.Count > 0)
            {
                var errorMessage = string.Join(Environment.NewLine, errorMessages);
                MessageBox.Show($"部分 PLC 连接失败: {errorMessage}");
            }
        }
        private void Update(object e)
        {
            while (ThreadRunning)
            {
                var item = e as IPLC;
                try
                {
                    if (item != null && item.Connected)
                    {
                        item?.Update();
                    }
                }
                catch (Exception ex)
                {
                    Thread.Sleep(1000);
                }
                Thread.Sleep(100);
            }
        }
        #endregion


        public List<ToPLCInteraceNode> GetTreeData()
        {
            return Machine.Instance.ConfigDbs.ToPLCInteraceNodeRepository.GetAsNoTrackingAllList();
        }
        public List<ToPLCInteraceNode> GetTreeDataFresh()
        {
            // 强制使用全新上下文获取数据
            using (var freshContext = ConfigDbs.ToPLCInteraceNodeRepository.GetDbContext())
            {
                return freshContext.Set<ToPLCInteraceNode>()
                    .AsNoTracking() // 禁止实体追踪
                    .ToList();
            }
        }
        public List<TreeViewItem> BuildTree(List<ToPLCInteraceNode> filteredData = null)
        {
            var rootNodes = new Dictionary<string, TreeViewItem>();
            var data = filteredData ?? GetTreeData();

            foreach (var item in data)
            {
                var pathParts = item.GroupName.Split('/');
                TreeViewItem currentNode = null;

                // 处理根节点
                if (!rootNodes.ContainsKey(pathParts[0]))
                {
                    rootNodes[pathParts[0]] = new TreeViewItem { Header = pathParts[0] };
                }
                currentNode = rootNodes[pathParts[0]];

                // 处理中间节点
                for (int i = 1; i < pathParts.Length; i++)
                {
                    var existingChild = FindChildNode(currentNode, pathParts[i]);
                    if (existingChild == null)
                    {
                        var newChild = new TreeViewItem { Header = pathParts[i] };
                        currentNode.Items.Add(newChild);
                        currentNode = newChild;
                    }
                    else
                    {
                        currentNode = existingChild;
                    }
                }

                // 添加最终子节点
                var finalChild = FindChildNode(currentNode, item.NodeName);
                if (finalChild == null)
                {
                    var newFinalChild = new TreeViewItem { Header = item.NodeName };
                    currentNode.Items.Add(newFinalChild);
                }
            }

            return rootNodes.Values.ToList();
        }
        private TreeViewItem FindChildNode(TreeViewItem parent, string header)
        {
            foreach (TreeViewItem child in parent.Items)
            {
                if (child.Header.ToString() == header)
                {
                    return child;
                }
            }
            return null;
        }

        /// <summary>
        /// 插入组到数据库
        /// </summary>
        /// <param name="groupPath"></param>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="Exception"></exception>
        public void InsertGroupToDb(string fileName, string groupPath)
        {
            if (string.IsNullOrEmpty(groupPath))
            {
                throw new ArgumentException("组路径不能为空", nameof(groupPath));
            }
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("文件名不能为空", nameof(fileName));
            }

            try
            {
                // 获取下一个可用的 Index 值
                var allNodes = Machine.Instance.ConfigDbs.ToPLCInteraceNodeRepository.GetAllList();
                int nextIndex = allNodes.Count > 0 ? allNodes.Max(node => node.Index) + 1 : 1;

                ToPLCInteraceNode newNode = new ToPLCInteraceNode
                {
                    Index = nextIndex,
                    FileName = fileName,
                    GroupName = groupPath,
                    NodeName = "XXXX",
                    NodePreSetValue = "XXXX",
                    Type = "XXXX",
                    NodeDescription = "XXXX",
                    NodeWrite = "XXXX",
                    NodeRead = "XXXX",

                };

                Machine.Instance.ConfigDbs.ToPLCInteraceNodeRepository.Insert(newNode);
            }
            catch (Exception ex)
            {
                throw new Exception($"向数据库插入组时出错: {ex.Message}", ex);
            }
        }

    }
}